package org.example.juc;

import org.example.juc.lock.SimpleMockLock;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 验证volatile原子性问题
 */
public class VolatileTest {

    public volatile int counter = 0;

    private static Unsafe unsafe;

    private static long valueOffset;

    private ReentrantLock lock = new ReentrantLock();

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);

            // 获取的是字段在对象的地址
            Field counterField = VolatileTest.class.getDeclaredField("counter");
            counterField.setAccessible(true);
            valueOffset = unsafe.objectFieldOffset(counterField);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void increment() {
//        // 1. CAS自旋
//        for (;;) {
//            int oldValue = counter;
//            // 更新了这个地址的值，不需要再次执行counter++操作了
//            if (unsafe.compareAndSwapInt(this, valueOffset, oldValue, oldValue + 1)) {
//                // counter
//                return;
//            }
//        }

//        // 2. 通过可重入锁来进行控制
//        lock.lock();
//        counter++;
//        lock.unlock();

        // CLH锁队列
        counter++;
    }

    public static void main(String[] args) throws Exception {
        VolatileTest test = new VolatileTest();
        ExecutorService service = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(10);
        int MAX_THREAD = 10;
        SimpleMockLock mockLock = new SimpleMockLock();
        for (int i = 0; i < MAX_THREAD; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    mockLock.lock();
                    try {
                        for (int j = 0; j < 10000; j++) {
                            test.increment();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        mockLock.unlock();

                        latch.countDown();
                        System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
                    }
                }
            });
        }

        latch.await();
        System.out.println("counter = " + test.counter);
    }
}
